package com.plian.Tools.office;


import freemarker.core.XMLOutputFormat;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.Version;
import org.apache.poi.xwpf.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 * Word文档工具类
 */
public class WordUtil {
    private static final Logger log = LoggerFactory.getLogger(WordUtil.class);

    /**
     * 使用FreeMarker自动生成Word文档
     *
     * @param dataMap 生成Word文档所需要的数据
     */
    public static File generateWord(Map<String, Object> dataMap, String path, String fileName, String ftlName) throws Exception {
        // 设置FreeMarker的版本和编码格式
        Configuration configuration = new Configuration(new Version("2.3.28"));
        configuration.setDefaultEncoding("UTF-8");
        configuration.setOutputFormat(XMLOutputFormat.INSTANCE);
        // 设置FreeMarker生成Word文档所需要的模板的路径

        configuration.setClassForTemplateLoading(WordUtil.class, "/pdf");
        // 设置FreeMarker生成Word文档所需要的模板
//        Template t = configuration.getTemplate("productionSafetyAccidents.ftl", "UTF-8");
        Template t = configuration.getTemplate(ftlName, "UTF-8");
        creatFile(path, fileName);//创建文件
        // 创建一个Word文档的输出流输出文件
        File outFile = new File(path + "/" + fileName);
//        System.out.println("word路径："+outFile.getPath());
        //如果输出目标文件夹不存在，则创建
        if (!outFile.getParentFile().exists()) {
            outFile.getParentFile().mkdirs();
        }
        Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8"));
        //FreeMarker使用Word模板和数据生成Word文档
        t.process(dataMap, out);
        out.flush();
        out.close();
        return outFile;
    }

    private static void creatFile(String path, String fileName) throws Exception {
        File f = new File(path);
        if (!f.exists()) {
            f.mkdirs();
        }
        File file = new File(f, fileName);
        if (!file.exists()) {
            file.createNewFile();
        }
    }

    /**
     * @Author: Take-off
     * @Description: //TODO 替换word文本
     * @Date: 10:23 AM 2023/2/16
     * @Param: [map, path, fileName, demo]
     * @return: java.io.File
     **/
    public static File downloadReportFile(Map<String, String> map, String path, String fileName, InputStream in) {
        XWPFDocument document = null;
        File outFile = new File(path + "/" + fileName);
        try {
            //获取docx解析对象
            document = new XWPFDocument(in);
            WordUtil.changeText(document, map);
            FileOutputStream outStream = new FileOutputStream(outFile);
            document.write(outStream);
            outStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return outFile;
    }

    /**
     *
     * @param map      data
     * @param path     路径
     * @param fileName 文件名称
     * @param in       模版对象
     * @return
     */
    public static File createReportFile(Map<String, String> map, String path, String fileName, InputStream in) {
        XWPFDocument document = null;
        File outFile = new File(path + "/" + fileName);
        try {
            //如果输出目标文件夹不存在，则创建
            if (!outFile.getParentFile().exists()) {
                outFile.getParentFile().mkdirs();
            }
            //获取docx解析对象
            document = new XWPFDocument(in);
            WordUtil.changeText(document, map);
            FileOutputStream outStream = new FileOutputStream(outFile);
            document.write(outStream);
            outStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return outFile;
    }

    /**
     * 替换段落文本
     *
     * @param document docx解析对象
     * @param textMap  需要替换的信息集合
     */
    public static void changeText(XWPFDocument document, Map<String, String> textMap) {
        //获取段落集合
        List<XWPFParagraph> paragraphs = document.getParagraphs();
        for (XWPFParagraph paragraph : paragraphs) {
            //获取到段落中的所有文本内容
            String text = paragraph.getText();
            //判断此段落中是否有需要进行替换的文本
            if (checkText(text)) {
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                    //替换模板原来位置
                    run.setText(changeValue(run.toString(), textMap), 0);
                }
            }
        }
        replaceTableValue(document, textMap);
    }

    public static void replaceTableValue(XWPFDocument document, Map<String, String> textMap) {
        Iterator<XWPFTable> it = document.getTablesIterator();
        //表格内容替换添加
        while (it.hasNext()) {
            XWPFTable table = it.next();
            int rcount = table.getNumberOfRows();
            for (int i = 0; i < rcount; i++) {
                XWPFTableRow row = table.getRow(i);
                List<XWPFTableCell> cells = row.getTableCells();
                for (XWPFTableCell cell : cells) {
                    if (checkText(cell.getText())) {
                        List<XWPFParagraph> tableParagraphsList = cell.getParagraphs();
                        for (XWPFParagraph paragraph : tableParagraphsList) {
                            String text = paragraph.getText(); //获取到段落中的所有文本内容
                            if (checkText(text)) { //判断此段落中是否有需要进行替换的文本
                                List<XWPFRun> runs = paragraph.getRuns();
                                for (XWPFRun run : runs) {
                                    run.setText(changeValue(text, textMap), 0);//替换模板原来位置
                                }
                            }
                        }
                    }

                }
            }
        }
    }

    /**
     * 判断文本中是否包含$
     *
     * @param text 文本
     * @return 包含返回true, 不包含返回false
     */
    public static boolean checkText(String text) {
        boolean check = false;
        if (text.contains("$")) {
            check = true;
        }
        return check;
    }

    /**
     * 匹配传入信息集合与模板
     *
     * @param value   模板需要替换的区域
     * @param textMap 传入信息集合
     * @return 模板需要替换区域信息集合对应值
     */
    public static String changeValue(String value, Map<String, String> textMap) {
        Set<Map.Entry<String, String>> textSets = textMap.entrySet();
        for (Map.Entry<String, String> textSet : textSets) {
            //匹配模板与替换值 格式${key}
            String key = "${" + textSet.getKey() + "}";
            if (value.contains(key)) {
                value = textSet.getValue();
            }
        }
        //模板未匹配到区域替换为空
        if (checkText(value)) {
            value = "";
        }
        return value;
    }
}

